package com.dayu.tcp.future;

import com.dayu.tcp.exception.SocketRuntimeException;
import com.dayu.tcp.logging.Log;
import com.dayu.tcp.logging.LogFactory;
import io.netty.channel.Channel;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author yehangtech
 * @date 2025/4/6 17:45
 * @description 赋予大禹TCP，异步转同步的能力
 */
public class InvokeFuture {

    private static final Log log = LogFactory.getLog(InvokeFuture.class);

    protected Object result;

    /**
     * 标志是否完成，完成状态:有可能失败 也有可能成功
     */
    protected AtomicBoolean done = new AtomicBoolean(false);

    public boolean isDone() {
        return done.get();
    }

    /**
     * 标志是否成功，如果成功则一定完成
     */
    protected AtomicBoolean success = new AtomicBoolean(false);

    public boolean isSuccess() {
        return success.get();
    }

    protected Semaphore semaphore = new Semaphore(0);

    @Getter
    protected Throwable cause;

    @Getter
    @Setter
    protected Channel channel;

    @Getter
    @Setter
    protected Object attachment;

    protected List<InvokeFutureListener> listenerList = new ArrayList<>();

    public void addListener(@NonNull InvokeFutureListener listener) {
        notifyListener(listener);
        listenerList.add(listener);
    }

    private void notifyListener(@NonNull InvokeFutureListener listener) {
        if (isDone()) {
            try {
                listener.operationComplete(this);
            } catch (Exception ex) {
                log.error("Failed to notify listener when operation completed.", ex);
            }
        }
    }

    private void notifyAllListener() {
        if (isDone()) {
            for (InvokeFutureListener listener : listenerList) {
                try {
                    listener.operationComplete(this);
                } catch (Exception ex) {
                    log.error("Failed to notify listener when operation completed.", ex);
                }
            }
        }
    }

    public Object getResult() {
        if (!isDone()) {
            try {
                semaphore.acquire();
            } catch (InterruptedException ex) {
                throw new RuntimeException(ex);
            }
        }
        if (cause != null) {
            throw new SocketRuntimeException(cause);
        }
        return this.result;
    }

    public Object getResult(long timeout, TimeUnit timeUnit) {
        if (!isDone()) {
            try {
                if (!semaphore.tryAcquire(timeout, timeUnit) && !isDone()) {
                    setCause(new SocketRuntimeException("time out."));
                }
            } catch (InterruptedException ex) {
                throw new RuntimeException(ex);
            }
        }
        if (cause != null) {
            throw new SocketRuntimeException(cause);
        }
        return this.result;
    }

    /**
     * 调用此方法，代表执行失败，立即唤醒线程不再等待
     * @param cause
     */
    public void setCause(Throwable cause) {
        this.cause = cause;
        done.set(true);
        success.set(false);
        semaphore.release(Integer.MAX_VALUE - semaphore.availablePermits());//立即唤醒
        notifyAllListener();
    }

    /**
     * 调用此方法，代表执行成功，立即唤醒线程不再等待
     * @param result
     */
    public void setResult(Object result) {
        this.result = result;
        done.set(true);
        success.set(true);
        semaphore.release(Integer.MAX_VALUE - semaphore.availablePermits());//立即唤醒
        notifyAllListener();
    }


}
